diff options
| author | F. Jason Park | 2023-04-30 07:12:56 -0700 |
|---|---|---|
| committer | F. Jason Park | 2023-05-05 17:18:01 -0700 |
| commit | 35dd1ade7f1e583f736e6f707343402fe868daec (patch) | |
| tree | bc1a0022b297fd89c0acea30172e95ed5a9f0f98 | |
| parent | 3a5a6fce957468be5ef0a8ac76fec8507c3e4e99 (diff) | |
| download | emacs-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-NEWS | 6 | ||||
| -rw-r--r-- | lisp/erc/erc-common.el | 14 | ||||
| -rw-r--r-- | lisp/erc/erc-goodies.el | 5 | ||||
| -rw-r--r-- | lisp/erc/erc-ring.el | 4 | ||||
| -rw-r--r-- | lisp/erc/erc.el | 135 | ||||
| -rw-r--r-- | test/lisp/erc/erc-tests.el | 101 |
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 | |||
| 187 | goes for ERC's imenu integration, which has 'imenu' now appearing in | 187 | goes for ERC's imenu integration, which has 'imenu' now appearing in |
| 188 | the default value of 'erc-modules'. | 188 | the default value of 'erc-modules'. |
| 189 | 189 | ||
| 190 | *** Prompt input is split before 'erc-pre-send-functions' has a say. | ||
| 191 | Hook members are now treated to input whose lines have already been | ||
| 192 | adjusted to fall within the allowed length limit. For convenience, | ||
| 193 | third-party code can request that the final input be "re-filled" prior | ||
| 194 | to 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. |
| 191 | Previously, ERC's prompt and its input marker disappeared while | 197 | Previously, ERC's prompt and its input marker disappeared while |
| 192 | running hooks during message insertion, and the position of its | 198 | running 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. |
| 339 | Commands listed in `erc-insert-this' know how to display | 339 | Commands listed in `erc-insert-this' know how to display |
| 340 | themselves." | 340 | themselves." |
| 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 |
| 48 | be recalled using M-p and M-n." | 48 | be 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 | |||
| 1100 | This hook runs after protocol line splitting has taken place, so | ||
| 1101 | the value of `string' is originally \"pre-filled\". If you need | ||
| 1102 | ERC to refill the entire payload before sending it, set the | ||
| 1103 | `refoldp' slot to a non-nil value. Preformatted text and encoded | ||
| 1104 | subprotocols 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 | 1115 | ERC runs this before clearing the prompt and before running any | |
| 1109 | (defvar erc--pre-send-split-functions '(erc--discard-trailing-multiline-nulls | 1116 | send-related hooks, such as `erc-pre-send-functions'. Thus, it's |
| 1110 | erc--split-lines) | 1117 | quite \"safe\" to bail out of this hook with a `user-error', if |
| 1111 | "Special hook for modifying individual lines in multiline prompt input. | 1118 | necessary. The hook's members are called with one argument, an |
| 1112 | The functions are called with one argument, an `erc--input-split' | 1119 | `erc--input-split' struct, which they can optionally modify. |
| 1113 | struct, which they can optionally modify. | ||
| 1114 | 1120 | ||
| 1115 | The struct has five slots: | 1121 | The 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 | ||
| 1123 | The `string' field is effectively read-only. When `cmdp' is | 1130 | When `cmdp' is non-nil, all but the first line will be discarded.") |
| 1124 | non-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. |
| 1166 | This hook is called just after `erc-send-pre-hook' when the values | 1172 | ERC runs this just after `erc-pre-send-functions' if its shared |
| 1167 | of `erc-send-this' and `erc-insert-this' are both t. | 1173 | `erc-input' object's `sendp' and `insertp' slots remain non-nil. |
| 1168 | While this hook is run, narrowing is in effect and `current-buffer' is | 1174 | While this hook is run, narrowing is in effect and `current-buffer' is |
| 1169 | the buffer where the text got inserted. | 1175 | the 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." | |||
| 6155 | Called with latest input string submitted by user and the list of | 6163 | Called with latest input string submitted by user and the list of |
| 6156 | lines produced by splitting it. If any member function returns | 6164 | lines produced by splitting it. If any member function returns |
| 6157 | non-nil, processing is abandoned and input is left untouched. | 6165 | non-nil, processing is abandoned and input is left untouched. |
| 6158 | When the returned value is a string, pass it to `erc-error'.") | 6166 | When 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. | ||
| 6249 | Sequester some of the back and forth involved in honoring old | ||
| 6250 | interfaces, such as the reconstituting and re-splitting of | ||
| 6251 | multiline input. Optionally readjust lines to protocol length | ||
| 6252 | limits and pad empty ones, knowing full well that additional | ||
| 6253 | processing may still corrupt messages before they reach the send | ||
| 6254 | queue. 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. |
| 6228 | It is assumed that the input and the prompt is already deleted. | 6295 | It 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 () |