aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorF. Jason Park2023-04-30 07:12:56 -0700
committerF. Jason Park2023-05-05 17:18:01 -0700
commit35dd1ade7f1e583f736e6f707343402fe868daec (patch)
treebc1a0022b297fd89c0acea30172e95ed5a9f0f98
parent3a5a6fce957468be5ef0a8ac76fec8507c3e4e99 (diff)
downloademacs-35dd1ade7f1e583f736e6f707343402fe868daec.tar.gz
emacs-35dd1ade7f1e583f736e6f707343402fe868daec.zip
Preprocess prompt input linewise in ERC
* etc/ERC-NEWS: Mention revised role of `erc-pre-send-functions' relative to line splitting. * lisp/erc/erc-common.el (erc-input): Add new slot `refoldp' to allow `erc-pre-send-functions' members to indicate that splitting should occur a second time after all members have had their say. (erc--input-split): Specify some defaults for overridden slots and explicitly declare some types for good measure. * lisp/erc/erc-goodies.el (erc-noncommands-mode, erc-noncommands-enable, erc-noncommands-disable): Replace `erc-pre-send-functions' with `erc--input-review-functions'. * lisp/erc/erc-ring.el (erc-ring-enable, erc-ring-disable, erc-ring-mode): Subscribe to `erc--input-review-functions' instead of `erc-pre-send-functions' for `erc--add-to-input-ring'. * lisp/erc/erc.el (erc-pre-send-functions): Note some nuances regarding line splitting in doc string and note that a new slot is available. (erc--pre-send-split-functions, erc--input-review-functions): Rename former to latter, while also obsoleting. Remove large comment. Add new default member `erc--run-input-validation-checks'. (erc-send-modify-hook): Replace the obsolete `erc-send-pre-hook' and `erc-send-this' with `erc-pre-send-functions' in doc string. (erc--check-prompt-input-for-excess-lines): Don't trim trailing blanks. Rework to also report overages in characters as well as lines. (erc--run-input-validation-hooks): New function to adapt an `erc--input-split' object to `erc--check-prompt-input-functions'. (erc-send-current-line): Run `erc--input-review-functions' in place of the validation hooks they've subsumed. Call `erc--send-input-lines' instead of the now retired but not deprecated `erc-send-input'. (erc--run-send-hooks, erc--send-input-lines): New functions that together form an alternate version of `erc-send-input'. They operate on input linewise but make accommodations for older interfaces. * test/lisp/erc/erc-tests.el (erc-ring-previous-command): Replace `erc-pre-send-functions' with `erc--input-review-functions'. (erc-tests--with-process-input-spy): Shadow `erc--input-review-functions'. (erc-check-prompt-input-for-excess-lines): Don't expect trailing blanks to be trimmed. (erc--run-send-hooks): New test. (Bug#62947)
-rw-r--r--etc/ERC-NEWS6
-rw-r--r--lisp/erc/erc-common.el14
-rw-r--r--lisp/erc/erc-goodies.el5
-rw-r--r--lisp/erc/erc-ring.el4
-rw-r--r--lisp/erc/erc.el135
-rw-r--r--test/lisp/erc/erc-tests.el101
6 files changed, 218 insertions, 47 deletions
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 2cf2743701a..3907b7bc5f2 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -187,6 +187,12 @@ The 'fill' module is now defined by 'define-erc-module'. The same
187goes for ERC's imenu integration, which has 'imenu' now appearing in 187goes for ERC's imenu integration, which has 'imenu' now appearing in
188the default value of 'erc-modules'. 188the default value of 'erc-modules'.
189 189
190*** Prompt input is split before 'erc-pre-send-functions' has a say.
191Hook members are now treated to input whose lines have already been
192adjusted to fall within the allowed length limit. For convenience,
193third-party code can request that the final input be "re-filled" prior
194to being sent. See doc string for details.
195
190*** ERC's prompt survives the insertion of user input and messages. 196*** ERC's prompt survives the insertion of user input and messages.
191Previously, ERC's prompt and its input marker disappeared while 197Previously, ERC's prompt and its input marker disappeared while
192running hooks during message insertion, and the position of its 198running hooks during message insertion, and the position of its
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 708cdb0c422..86d78768374 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -30,8 +30,10 @@
30(defvar erc--casemapping-rfc1459-strict) 30(defvar erc--casemapping-rfc1459-strict)
31(defvar erc-channel-users) 31(defvar erc-channel-users)
32(defvar erc-dbuf) 32(defvar erc-dbuf)
33(defvar erc-insert-this)
33(defvar erc-log-p) 34(defvar erc-log-p)
34(defvar erc-modules) 35(defvar erc-modules)
36(defvar erc-send-this)
35(defvar erc-server-process) 37(defvar erc-server-process)
36(defvar erc-server-users) 38(defvar erc-server-users)
37(defvar erc-session-server) 39(defvar erc-session-server)
@@ -49,10 +51,14 @@
49(declare-function widget-type "wid-edit" (widget)) 51(declare-function widget-type "wid-edit" (widget))
50 52
51(cl-defstruct erc-input 53(cl-defstruct erc-input
52 string insertp sendp) 54 string insertp sendp refoldp)
53 55
54(cl-defstruct (erc--input-split (:include erc-input)) 56(cl-defstruct (erc--input-split (:include erc-input
55 lines cmdp) 57 (string :read-only)
58 (insertp erc-insert-this)
59 (sendp erc-send-this)))
60 (lines nil :type (list-of string))
61 (cmdp nil :type boolean))
56 62
57(cl-defstruct (erc-server-user (:type vector) :named) 63(cl-defstruct (erc-server-user (:type vector) :named)
58 ;; User data 64 ;; User data
diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index 6235de5f1c0..cc60ba0018b 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -338,8 +338,9 @@ does not appear in the ERC buffer after the user presses ENTER.")
338 "This mode distinguishes non-commands. 338 "This mode distinguishes non-commands.
339Commands listed in `erc-insert-this' know how to display 339Commands listed in `erc-insert-this' know how to display
340themselves." 340themselves."
341 ((add-hook 'erc-pre-send-functions #'erc-send-distinguish-noncommands)) 341 ((add-hook 'erc--input-review-functions #'erc-send-distinguish-noncommands))
342 ((remove-hook 'erc-pre-send-functions #'erc-send-distinguish-noncommands))) 342 ((remove-hook 'erc--input-review-functions
343 #'erc-send-distinguish-noncommands)))
343 344
344(defun erc-send-distinguish-noncommands (state) 345(defun erc-send-distinguish-noncommands (state)
345 "If STR is an ERC non-command, set `insertp' in STATE to nil." 346 "If STR is an ERC non-command, set `insertp' in STATE to nil."
diff --git a/lisp/erc/erc-ring.el b/lisp/erc/erc-ring.el
index 2451ac56f6f..4534e913204 100644
--- a/lisp/erc/erc-ring.el
+++ b/lisp/erc/erc-ring.el
@@ -46,10 +46,10 @@
46(define-erc-module ring nil 46(define-erc-module ring nil
47 "Stores input in a ring so that previous commands and messages can 47 "Stores input in a ring so that previous commands and messages can
48be recalled using M-p and M-n." 48be recalled using M-p and M-n."
49 ((add-hook 'erc-pre-send-functions #'erc-add-to-input-ring) 49 ((add-hook 'erc--input-review-functions #'erc-add-to-input-ring 90)
50 (define-key erc-mode-map "\M-p" #'erc-previous-command) 50 (define-key erc-mode-map "\M-p" #'erc-previous-command)
51 (define-key erc-mode-map "\M-n" #'erc-next-command)) 51 (define-key erc-mode-map "\M-n" #'erc-next-command))
52 ((remove-hook 'erc-pre-send-functions #'erc-add-to-input-ring) 52 ((remove-hook 'erc--input-review-functions #'erc-add-to-input-ring)
53 (define-key erc-mode-map "\M-p" #'undefined) 53 (define-key erc-mode-map "\M-p" #'undefined)
54 (define-key erc-mode-map "\M-n" #'undefined))) 54 (define-key erc-mode-map "\M-n" #'undefined)))
55 55
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index bc2285a5560..72ec8134eab 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1094,34 +1094,40 @@ The struct has three slots:
1094 1094
1095 `string': The current input string. 1095 `string': The current input string.
1096 `insertp': Whether the string should be inserted into the erc buffer. 1096 `insertp': Whether the string should be inserted into the erc buffer.
1097 `sendp': Whether the string should be sent to the irc server." 1097 `sendp': Whether the string should be sent to the irc server.
1098 `refoldp': Whether the string should be re-split per protocol limits.
1099
1100This hook runs after protocol line splitting has taken place, so
1101the value of `string' is originally \"pre-filled\". If you need
1102ERC to refill the entire payload before sending it, set the
1103`refoldp' slot to a non-nil value. Preformatted text and encoded
1104subprotocols should probably be handled manually."
1098 :group 'erc 1105 :group 'erc
1099 :type 'hook 1106 :type 'hook
1100 :version "27.1") 1107 :version "27.1")
1101 1108
1102;; This is being auditioned for possible exporting (as a custom hook 1109(define-obsolete-variable-alias 'erc--pre-send-split-functions
1103;; option). Likewise for (public versions of) `erc--input-split' and 1110 'erc--input-review-functions "30.1")
1104;; `erc--discard-trailing-multiline-nulls'. If unneeded, we'll just 1111(defvar erc--input-review-functions '(erc--discard-trailing-multiline-nulls
1105;; run the latter on the input after `erc-pre-send-functions', and 1112 erc--split-lines
1106;; remove this hook and the struct completely. IOW, if you need this, 1113 erc--run-input-validation-checks)
1107;; please say so. 1114 "Special hook for reviewing and modifying prompt input.
1108 1115ERC runs this before clearing the prompt and before running any
1109(defvar erc--pre-send-split-functions '(erc--discard-trailing-multiline-nulls 1116send-related hooks, such as `erc-pre-send-functions'. Thus, it's
1110 erc--split-lines) 1117quite \"safe\" to bail out of this hook with a `user-error', if
1111 "Special hook for modifying individual lines in multiline prompt input. 1118necessary. The hook's members are called with one argument, an
1112The functions are called with one argument, an `erc--input-split' 1119`erc--input-split' struct, which they can optionally modify.
1113struct, which they can optionally modify.
1114 1120
1115The struct has five slots: 1121The struct has five slots:
1116 1122
1117 `string': the input string delivered by `erc-pre-send-functions' 1123 `string': the original input as a read-only reference
1118 `insertp': whether to insert the lines into the buffer 1124 `insertp': same as in `erc-pre-send-functions'
1119 `sendp': whether the lines should be sent to the IRC server 1125 `sendp': same as in `erc-pre-send-functions'
1126 `refoldp': same as in `erc-pre-send-functions'
1120 `lines': a list of lines to be sent, each one a `string' 1127 `lines': a list of lines to be sent, each one a `string'
1121 `cmdp': whether to interpret input as a command, like /ignore 1128 `cmdp': whether to interpret input as a command, like /ignore
1122 1129
1123The `string' field is effectively read-only. When `cmdp' is 1130When `cmdp' is non-nil, all but the first line will be discarded.")
1124non-nil, all but the first line will be discarded.")
1125 1131
1126(defvar erc-insert-this t 1132(defvar erc-insert-this t
1127 "Insert the text into the target buffer or not. 1133 "Insert the text into the target buffer or not.
@@ -1163,8 +1169,8 @@ preserve point if needed."
1163 1169
1164(defcustom erc-send-modify-hook nil 1170(defcustom erc-send-modify-hook nil
1165 "Sending hook for functions that will change the text's appearance. 1171 "Sending hook for functions that will change the text's appearance.
1166This hook is called just after `erc-send-pre-hook' when the values 1172ERC runs this just after `erc-pre-send-functions' if its shared
1167of `erc-send-this' and `erc-insert-this' are both t. 1173`erc-input' object's `sendp' and `insertp' slots remain non-nil.
1168While this hook is run, narrowing is in effect and `current-buffer' is 1174While this hook is run, narrowing is in effect and `current-buffer' is
1169the buffer where the text got inserted. 1175the buffer where the text got inserted.
1170 1176
@@ -6106,16 +6112,18 @@ is empty or consists of one or more spaces, tabs, or form-feeds."
6106(defun erc--check-prompt-input-for-excess-lines (_ lines) 6112(defun erc--check-prompt-input-for-excess-lines (_ lines)
6107 "Return non-nil when trying to send too many LINES." 6113 "Return non-nil when trying to send too many LINES."
6108 (when erc-inhibit-multiline-input 6114 (when erc-inhibit-multiline-input
6109 ;; Assume `erc--discard-trailing-multiline-nulls' is set to run 6115 (let ((max (if (eq erc-inhibit-multiline-input t)
6110 (let ((reversed (seq-drop-while #'string-empty-p (reverse lines)))
6111 (max (if (eq erc-inhibit-multiline-input t)
6112 2 6116 2
6113 erc-inhibit-multiline-input)) 6117 erc-inhibit-multiline-input))
6114 (seen 0) 6118 (seen 0)
6115 msg) 6119 last msg)
6116 (while (and (pop reversed) (< (cl-incf seen) max))) 6120 (while (and lines (setq last (pop lines)) (< (cl-incf seen) max)))
6117 (when (= seen max) 6121 (when (= seen max)
6118 (setq msg (format "(exceeded by %d)" (1+ (length reversed)))) 6122 (push last lines)
6123 (setq msg
6124 (format "-- exceeded by %d (%d chars)"
6125 (length lines)
6126 (apply #'+ (mapcar #'length lines))))
6119 (unless (and erc-ask-about-multiline-input 6127 (unless (and erc-ask-about-multiline-input
6120 (y-or-n-p (concat "Send input " msg "?"))) 6128 (y-or-n-p (concat "Send input " msg "?")))
6121 (concat "Too many lines " msg)))))) 6129 (concat "Too many lines " msg))))))
@@ -6155,7 +6163,17 @@ is empty or consists of one or more spaces, tabs, or form-feeds."
6155Called with latest input string submitted by user and the list of 6163Called with latest input string submitted by user and the list of
6156lines produced by splitting it. If any member function returns 6164lines produced by splitting it. If any member function returns
6157non-nil, processing is abandoned and input is left untouched. 6165non-nil, processing is abandoned and input is left untouched.
6158When the returned value is a string, pass it to `erc-error'.") 6166When the returned value is a string, ERC passes it to `erc-error'.")
6167
6168(defun erc--run-input-validation-checks (state)
6169 "Run input checkers from STATE, an `erc--input-split' object."
6170 (when-let ((msg (run-hook-with-args-until-success
6171 'erc--check-prompt-input-functions
6172 (erc--input-split-string state)
6173 (erc--input-split-lines state))))
6174 (unless (stringp msg)
6175 (setq msg (format "Input error: %S" msg)))
6176 (user-error msg)))
6159 6177
6160(defun erc-send-current-line () 6178(defun erc-send-current-line ()
6161 "Parse current line and send it to IRC." 6179 "Parse current line and send it to IRC."
@@ -6170,12 +6188,15 @@ When the returned value is a string, pass it to `erc-error'.")
6170 (eolp)) 6188 (eolp))
6171 (expand-abbrev)) 6189 (expand-abbrev))
6172 (widen) 6190 (widen)
6173 (if-let* ((str (erc-user-input)) 6191 (let* ((str (erc-user-input))
6174 (msg (run-hook-with-args-until-success 6192 (state (make-erc--input-split
6175 'erc--check-prompt-input-functions str 6193 :string str
6176 (split-string str erc--input-line-delim-regexp)))) 6194 :insertp erc-insert-this
6177 (when (stringp msg) 6195 :sendp erc-send-this
6178 (erc-error msg)) 6196 :lines (split-string
6197 str erc--input-line-delim-regexp)
6198 :cmdp (string-match erc-command-regexp str))))
6199 (run-hook-with-args 'erc--input-review-functions state)
6179 (let ((inhibit-read-only t) 6200 (let ((inhibit-read-only t)
6180 (old-buf (current-buffer))) 6201 (old-buf (current-buffer)))
6181 (progn ; unprogn this during next major surgery 6202 (progn ; unprogn this during next major surgery
@@ -6183,7 +6204,7 @@ When the returned value is a string, pass it to `erc-error'.")
6183 ;; Kill the input and the prompt 6204 ;; Kill the input and the prompt
6184 (delete-region erc-input-marker (erc-end-of-input-line)) 6205 (delete-region erc-input-marker (erc-end-of-input-line))
6185 (unwind-protect 6206 (unwind-protect
6186 (erc-send-input str 'skip-ws-chk) 6207 (erc--send-input-lines (erc--run-send-hooks state))
6187 ;; Fix the buffer if the command didn't kill it 6208 ;; Fix the buffer if the command didn't kill it
6188 (when (buffer-live-p old-buf) 6209 (when (buffer-live-p old-buf)
6189 (with-current-buffer old-buf 6210 (with-current-buffer old-buf
@@ -6223,6 +6244,52 @@ an `erc--input-split' object."
6223 (setf (erc--input-split-lines state) 6244 (setf (erc--input-split-lines state)
6224 (mapcan #'erc--split-line (erc--input-split-lines state))))) 6245 (mapcan #'erc--split-line (erc--input-split-lines state)))))
6225 6246
6247(defun erc--run-send-hooks (lines-obj)
6248 "Run send-related hooks that operate on the entire prompt input.
6249Sequester some of the back and forth involved in honoring old
6250interfaces, such as the reconstituting and re-splitting of
6251multiline input. Optionally readjust lines to protocol length
6252limits and pad empty ones, knowing full well that additional
6253processing may still corrupt messages before they reach the send
6254queue. Expect LINES-OBJ to be an `erc--input-split' object."
6255 (when (or erc-send-pre-hook erc-pre-send-functions)
6256 (with-suppressed-warnings ((lexical str) (obsolete erc-send-this))
6257 (defvar str) ; see note in string `erc-send-input'.
6258 (let* ((str (string-join (erc--input-split-lines lines-obj) "\n"))
6259 (erc-send-this (erc--input-split-sendp lines-obj))
6260 (erc-insert-this (erc--input-split-insertp lines-obj))
6261 (state (progn
6262 ;; This may change `str' and `erc-*-this'.
6263 (run-hook-with-args 'erc-send-pre-hook str)
6264 (make-erc-input :string str
6265 :insertp erc-insert-this
6266 :sendp erc-send-this))))
6267 (run-hook-with-args 'erc-pre-send-functions state)
6268 (setf (erc--input-split-sendp lines-obj) (erc-input-sendp state)
6269 (erc--input-split-insertp lines-obj) (erc-input-insertp state)
6270 ;; See note in test of same name re trailing newlines.
6271 (erc--input-split-lines lines-obj)
6272 (cl-nsubst " " "" (split-string (erc-input-string state)
6273 erc--input-line-delim-regexp)
6274 :test #'equal))
6275 (when (erc-input-refoldp state)
6276 (erc--split-lines lines-obj)))))
6277 (when (and (erc--input-split-cmdp lines-obj)
6278 (cdr (erc--input-split-lines lines-obj)))
6279 (user-error "Multiline command detected" ))
6280 lines-obj)
6281
6282(defun erc--send-input-lines (lines-obj)
6283 "Send lines in `erc--input-split-lines' object LINES-OBJ."
6284 (when (erc--input-split-sendp lines-obj)
6285 (dolist (line (erc--input-split-lines lines-obj))
6286 (unless (erc--input-split-cmdp lines-obj)
6287 (when (erc--input-split-insertp lines-obj)
6288 (erc-display-msg line)))
6289 (erc-process-input-line (concat line "\n")
6290 (null erc-flood-protect)
6291 (not (erc--input-split-cmdp lines-obj))))))
6292
6226(defun erc-send-input (input &optional skip-ws-chk) 6293(defun erc-send-input (input &optional skip-ws-chk)
6227 "Treat INPUT as typed in by the user. 6294 "Treat INPUT as typed in by the user.
6228It is assumed that the input and the prompt is already deleted. 6295It is assumed that the input and the prompt is already deleted.
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index b6702617aeb..be5a566a268 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -942,8 +942,8 @@
942 (should-not (local-variable-if-set-p 'erc-send-completed-hook)) 942 (should-not (local-variable-if-set-p 'erc-send-completed-hook))
943 (set (make-local-variable 'erc-send-completed-hook) nil) ; skip t (globals) 943 (set (make-local-variable 'erc-send-completed-hook) nil) ; skip t (globals)
944 ;; Just in case erc-ring-mode is already on 944 ;; Just in case erc-ring-mode is already on
945 (setq-local erc-pre-send-functions nil) 945 (setq-local erc--input-review-functions nil)
946 (add-hook 'erc-pre-send-functions #'erc-add-to-input-ring) 946 (add-hook 'erc--input-review-functions #'erc-add-to-input-ring)
947 ;; 947 ;;
948 (cl-letf (((symbol-function 'erc-process-input-line) 948 (cl-letf (((symbol-function 'erc-process-input-line)
949 (lambda (&rest _) 949 (lambda (&rest _)
@@ -1156,7 +1156,9 @@
1156 1156
1157(defun erc-tests--with-process-input-spy (test) 1157(defun erc-tests--with-process-input-spy (test)
1158 (with-current-buffer (get-buffer-create "FakeNet") 1158 (with-current-buffer (get-buffer-create "FakeNet")
1159 (let* ((erc-pre-send-functions 1159 (let* ((erc--input-review-functions
1160 (remove #'erc-add-to-input-ring erc--input-review-functions))
1161 (erc-pre-send-functions
1160 (remove #'erc-add-to-input-ring erc-pre-send-functions)) ; for now 1162 (remove #'erc-add-to-input-ring erc-pre-send-functions)) ; for now
1161 (inhibit-message noninteractive) 1163 (inhibit-message noninteractive)
1162 (erc-server-current-nick "tester") 1164 (erc-server-current-nick "tester")
@@ -1314,13 +1316,14 @@
1314 (ert-info ("With `erc-inhibit-multiline-input' as t (2)") 1316 (ert-info ("With `erc-inhibit-multiline-input' as t (2)")
1315 (let ((erc-inhibit-multiline-input t)) 1317 (let ((erc-inhibit-multiline-input t))
1316 (should-not (erc--check-prompt-input-for-excess-lines "" '("a"))) 1318 (should-not (erc--check-prompt-input-for-excess-lines "" '("a")))
1317 (should-not (erc--check-prompt-input-for-excess-lines "" '("a" ""))) 1319 ;; Does not trim trailing blanks.
1320 (should (erc--check-prompt-input-for-excess-lines "" '("a" "")))
1318 (should (erc--check-prompt-input-for-excess-lines "" '("a" "b"))))) 1321 (should (erc--check-prompt-input-for-excess-lines "" '("a" "b")))))
1319 1322
1320 (ert-info ("With `erc-inhibit-multiline-input' as 3") 1323 (ert-info ("With `erc-inhibit-multiline-input' as 3")
1321 (let ((erc-inhibit-multiline-input 3)) 1324 (let ((erc-inhibit-multiline-input 3))
1322 (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b"))) 1325 (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b")))
1323 (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b" ""))) 1326 (should (erc--check-prompt-input-for-excess-lines "" '("a" "b" "")))
1324 (should (erc--check-prompt-input-for-excess-lines "" '("a" "b" "c"))))) 1327 (should (erc--check-prompt-input-for-excess-lines "" '("a" "b" "c")))))
1325 1328
1326 (ert-info ("With `erc-ask-about-multiline-input'") 1329 (ert-info ("With `erc-ask-about-multiline-input'")
@@ -1399,6 +1402,94 @@
1399 1402
1400 (should-not calls)))))) 1403 (should-not calls))))))
1401 1404
1405
1406;; The behavior of `erc-pre-send-functions' differs between versions
1407;; in how hook members see and influence a trailing newline that's
1408;; part of the original prompt submission:
1409;;
1410;; 5.4: both seen and sent
1411;; 5.5: seen but not sent*
1412;; 5.6: neither seen nor sent*
1413;;
1414;; * requires `erc-send-whitespace-lines' for hook to run
1415;;
1416;; Two aspects that have remained consistent are
1417;;
1418;; - a final nonempty line in any submission is always sent
1419;; - a trailing newline appended by a hook member is always sent
1420;;
1421;; The last bullet would seem to contradict the "not sent" behavior of
1422;; 5.5 and 5.6, but what's actually happening is that exactly one
1423;; trailing newline is culled, so anything added always goes through.
1424;; Also, in ERC 5.6, all empty lines are actually padded, but this is
1425;; merely incidental WRT the above.
1426;;
1427;; Note that this test doesn't run any input-prep hooks and thus can't
1428;; account for the "seen" dimension noted above.
1429
1430(ert-deftest erc--run-send-hooks ()
1431 (with-suppressed-warnings ((obsolete erc-send-this)
1432 (obsolete erc-send-pre-hook))
1433 (should erc-insert-this)
1434 (should erc-send-this) ; populates `erc--input-split-sendp'
1435
1436 (let (erc-pre-send-functions erc-send-pre-hook)
1437
1438 (ert-info ("String preserved, lines rewritten, empties padded")
1439 (setq erc-pre-send-functions
1440 (lambda (o) (setf (erc-input-string o) "bar\n\nbaz\n")))
1441 (should (pcase (erc--run-send-hooks (make-erc--input-split
1442 :string "foo" :lines '("foo")))
1443 ((cl-struct erc--input-split
1444 (string "foo") (sendp 't) (insertp 't)
1445 (lines '("bar" " " "baz" " ")) (cmdp 'nil))
1446 t))))
1447
1448 (ert-info ("Multiline commands rejected")
1449 (should-error (erc--run-send-hooks (make-erc--input-split
1450 :string "/mycmd foo"
1451 :lines '("/mycmd foo")
1452 :cmdp t))))
1453
1454 (ert-info ("Single-line commands pass")
1455 (setq erc-pre-send-functions
1456 (lambda (o) (setf (erc-input-sendp o) nil
1457 (erc-input-string o) "/mycmd bar")))
1458 (should (pcase (erc--run-send-hooks (make-erc--input-split
1459 :string "/mycmd foo"
1460 :lines '("/mycmd foo")
1461 :cmdp t))
1462 ((cl-struct erc--input-split
1463 (string "/mycmd foo") (sendp 'nil) (insertp 't)
1464 (lines '("/mycmd bar")) (cmdp 't))
1465 t))))
1466
1467 (ert-info ("Legacy hook respected, special vars confined")
1468 (setq erc-send-pre-hook (lambda (_) (setq erc-send-this nil))
1469 erc-pre-send-functions (lambda (o) ; propagates
1470 (should-not (erc-input-sendp o))))
1471 (should (pcase (erc--run-send-hooks (make-erc--input-split
1472 :string "foo" :lines '("foo")))
1473 ((cl-struct erc--input-split
1474 (string "foo") (sendp 'nil) (insertp 't)
1475 (lines '("foo")) (cmdp 'nil))
1476 t)))
1477 (should erc-send-this))
1478
1479 (ert-info ("Request to resplit honored")
1480 (setq erc-send-pre-hook nil
1481 erc-pre-send-functions
1482 (lambda (o) (setf (erc-input-string o) "foo bar baz"
1483 (erc-input-refoldp o) t)))
1484 (let ((erc-split-line-length 8))
1485 (should
1486 (pcase (erc--run-send-hooks (make-erc--input-split
1487 :string "foo" :lines '("foo")))
1488 ((cl-struct erc--input-split
1489 (string "foo") (sendp 't) (insertp 't)
1490 (lines '("foo bar " "baz")) (cmdp 'nil))
1491 t))))))))
1492
1402;; Note: if adding an erc-backend-tests.el, please relocate this there. 1493;; Note: if adding an erc-backend-tests.el, please relocate this there.
1403 1494
1404(ert-deftest erc-message () 1495(ert-deftest erc-message ()