Improve erc-warn-about-blank-lines behavior
* etc/ERC-NEWS: Mention more detailed feedback when option `erc-warn-about-blank-lines' is non-nil. * lisp/erc/erc-common.el (erc--input-split): Add `abortp' slot to allow a premature exit while validating prompt input. * lisp/erc/erc.el (erc-warn-about-blank-lines): Clarify meaning of "blank lines" in doc string, and mention interaction with companion option `erc-send-whitespace-lines'. (erc-inhibit-multiline-input): Fix inaccurate description in doc string. (erc--input-review-functions): Move `erc--discard-trailing-multiline-nulls' to end of list, after `erc--run-input-validation-checks' so that the latter doesn't have to resplit the original input string in order to issue feedback. (erc--blank-in-multiline-input-p): Remove unused internal function originally slated to be part of ERC 5.6. (erc--check-prompt-input-for-something): New trivial validation function to check if the input is empty. (erc--count-blank-lines): New function that tallies up the number of blank and whitespace-only lines in the current input. One downside of this design is that this function's conclusions aren't shared with `erc--discard-trailing-multiline-nulls', which must decide on its own how many lines to strip. (erc--check-prompt-explanation): New variable. (erc--check-prompt-input-for-multiline-blanks): Rework significantly to provide more informative messages and more sensible behavior for common cases with respect to relevant option values. (erc--check-prompt-input-functions): Add new validation function `erc--check-prompt-for-something'. (erc--run-input-validation-checks): Set `abortp' slot of `erc--input-split' when hooks return a non-string, rather than generate an unhelpful fallback message. Also print a message when the variable `erc--check-prompt-explanation' is non-nil. (erc-send-current-line): When the `abortp' slot of the current `erc--input-split' object is non-nil, forgo normal input processing. This fixes a regression in 5.6-git, which previously emitted an error message when it should have just exited the command. (erc--discard-trailing-multiline-nulls): Always run, regardless of `erc-send-whitespace-lines', and leave a blank line behind when stripping a message consisting of only blank lines. (erc--run-send-hooks): Always run hooks and surrounding logic rather than only when hooks are populated. * test/lisp/erc/erc-tests.el (erc--refresh-prompt): Add assertion and use default value for `erc--input-review-functions'. (erc-ring-previous-command): Use default value for `erc--input-review-functions' and ensure `erc-current-nick' does not error. (erc--blank-in-multiline-input-p): Remove obsolete test. (erc--check-prompt-input-functions): Update expected message. (erc--discard-trailing-multiline-nulls, erc--count-blank-lines): New tests. (erc-tests--check-prompt-input--expect, erc-tests--check-prompt-input-messages): New helper variables. (erc--check-prompt-input-for-multiline-blanks, erc--check-prompt-input-for-multiline-blanks/explanations): New tests. (erc-send-whitespace-lines): Expect hook-processing logic to pad empty lines instead of deferring to `erc-send-input-line-function'. (Bug#66073)
This commit is contained in:
parent
8db56235cb
commit
a3c6ed0e36
4 changed files with 256 additions and 84 deletions
|
@ -221,6 +221,12 @@ atop any message. The new companion option 'erc-echo-timestamp-zone'
|
|||
determines the default timezone when not specified with a prefix
|
||||
argument.
|
||||
|
||||
** Option 'erc-warn-about-blank-lines' is more informative.
|
||||
Enabled by default, this option now produces more useful feedback
|
||||
whenever ERC rejects prompt input containing whitespace-only lines.
|
||||
When paired with option 'erc-send-whitespace-lines', ERC echoes a
|
||||
tally of blank lines padded and trailing blanks culled.
|
||||
|
||||
** Miscellaneous UX changes.
|
||||
Some minor quality-of-life niceties have finally made their way to
|
||||
ERC. For example, fool visibility has become togglable with the new
|
||||
|
@ -281,7 +287,7 @@ For starters, the 'cursor-sensor-functions' property no longer
|
|||
contains unique closures and thus no longer proves effective for
|
||||
traversing messages. To compensate, a new property, 'erc-timestamp',
|
||||
now spans message bodies but not the newlines delimiting them. Also
|
||||
affecting the `stamp' module is the deprecation of the function
|
||||
affecting the 'stamp' module is the deprecation of the function
|
||||
'erc-insert-aligned' and its removal from client code. Additionally,
|
||||
the module now merges its 'invisible' property with existing ones and
|
||||
includes all white space around stamps when doing so.
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
((obsolete erc-send-this))
|
||||
erc-send-this))))
|
||||
(lines nil :type (list-of string))
|
||||
(abortp nil :type (list-of symbol))
|
||||
(cmdp nil :type boolean))
|
||||
|
||||
(cl-defstruct (erc-server-user (:type vector) :named)
|
||||
|
|
151
lisp/erc/erc.el
151
lisp/erc/erc.el
|
@ -252,7 +252,14 @@ node `(auth) Top' and Info node `(erc) auth-source'.")
|
|||
:type 'boolean)
|
||||
|
||||
(defcustom erc-warn-about-blank-lines t
|
||||
"Warn the user if they attempt to send a blank line."
|
||||
"Warn the user if they attempt to send a blank line.
|
||||
When non-nil, ERC signals a `user-error' upon encountering prompt
|
||||
input containing empty or whitespace-only lines. When nil, ERC
|
||||
still inhibits sending but does so silently. With the companion
|
||||
option `erc-send-whitespace-lines' enabled, ERC sends pending
|
||||
input and prints a message in the echo area indicating the amount
|
||||
of padding and/or stripping applied, if any. Setting this option
|
||||
to nil suppresses such reporting."
|
||||
:group 'erc
|
||||
:type 'boolean)
|
||||
|
||||
|
@ -264,8 +271,8 @@ node `(auth) Top' and Info node `(erc) auth-source'.")
|
|||
(defcustom erc-inhibit-multiline-input nil
|
||||
"When non-nil, conditionally disallow input consisting of multiple lines.
|
||||
Issue an error when the number of input lines submitted for
|
||||
sending exceeds this value. The value t means disallow more
|
||||
than 1 line of input."
|
||||
sending meets or exceeds this value. The value t is synonymous
|
||||
with a value of 2 and means disallow more than 1 line of input."
|
||||
:package-version '(ERC . "5.5")
|
||||
:group 'erc
|
||||
:type '(choice integer boolean))
|
||||
|
@ -1095,9 +1102,9 @@ subprotocols should probably be handled manually."
|
|||
|
||||
(define-obsolete-variable-alias 'erc--pre-send-split-functions
|
||||
'erc--input-review-functions "30.1")
|
||||
(defvar erc--input-review-functions '(erc--discard-trailing-multiline-nulls
|
||||
erc--split-lines
|
||||
erc--run-input-validation-checks)
|
||||
(defvar erc--input-review-functions '(erc--split-lines
|
||||
erc--run-input-validation-checks
|
||||
erc--discard-trailing-multiline-nulls)
|
||||
"Special hook for reviewing and modifying prompt input.
|
||||
ERC runs this before clearing the prompt and before running any
|
||||
send-related hooks, such as `erc-pre-send-functions'. Thus, it's
|
||||
|
@ -6424,20 +6431,6 @@ holds off on submitting it, for obvious reasons."
|
|||
(defvar erc-command-regexp "^/\\([A-Za-z']+\\)\\(\\s-+.*\\|\\s-*\\)$"
|
||||
"Regular expression used for matching commands in ERC.")
|
||||
|
||||
(defun erc--blank-in-multiline-input-p (lines)
|
||||
"Detect whether LINES contains a blank line.
|
||||
When `erc-send-whitespace-lines' is in effect, return nil if
|
||||
LINES is multiline or the first line is non-empty. When
|
||||
`erc-send-whitespace-lines' is nil, return non-nil when any line
|
||||
is empty or consists of one or more spaces, tabs, or form-feeds."
|
||||
(catch 'return
|
||||
(let ((multilinep (cdr lines)))
|
||||
(dolist (line lines)
|
||||
(when (if erc-send-whitespace-lines
|
||||
(and (string-empty-p line) (not multilinep))
|
||||
(string-match (rx bot (* (in " \t\f")) eot) line))
|
||||
(throw 'return t))))))
|
||||
|
||||
(defun erc--check-prompt-input-for-excess-lines (_ lines)
|
||||
"Return non-nil when trying to send too many LINES."
|
||||
(when erc-inhibit-multiline-input
|
||||
|
@ -6457,13 +6450,78 @@ is empty or consists of one or more spaces, tabs, or form-feeds."
|
|||
(y-or-n-p (concat "Send input " msg "?")))
|
||||
(concat "Too many lines " msg))))))
|
||||
|
||||
(defun erc--check-prompt-input-for-multiline-blanks (_ lines)
|
||||
"Return non-nil when multiline prompt input has blank LINES."
|
||||
(when (erc--blank-in-multiline-input-p lines)
|
||||
(defun erc--check-prompt-input-for-something (string _)
|
||||
(when (string-empty-p string)
|
||||
(if erc-warn-about-blank-lines
|
||||
"Blank line - ignoring..."
|
||||
'invalid)))
|
||||
|
||||
(defun erc--count-blank-lines (lines)
|
||||
"Report on the number of whitespace-only and empty LINES.
|
||||
Return a list of (BLANKS TO-PAD TO-STRIP). Expect caller to know
|
||||
that BLANKS includes non-empty whitespace-only lines and that no
|
||||
padding or stripping has yet occurred."
|
||||
(let ((real 0) (total 0) (pad 0) (strip 0))
|
||||
(dolist (line lines)
|
||||
(if (string-match (rx bot (* (in " \t\f")) eot) line)
|
||||
(progn
|
||||
(cl-incf total)
|
||||
(if (zerop (match-end 0))
|
||||
(cl-incf strip)
|
||||
(cl-incf pad strip)
|
||||
(setq strip 0)))
|
||||
(cl-incf real)
|
||||
(unless (zerop strip)
|
||||
(cl-incf pad strip)
|
||||
(setq strip 0))))
|
||||
(when (and (zerop real) (not (zerop total)) (= total (+ pad strip)))
|
||||
(cl-incf strip (1- pad))
|
||||
(setq pad 1))
|
||||
(list total pad strip)))
|
||||
|
||||
(defvar erc--check-prompt-explanation nil
|
||||
"List of strings to print if no validator returns non-nil.")
|
||||
|
||||
(defun erc--check-prompt-input-for-multiline-blanks (_ lines)
|
||||
"Return non-nil when multiline prompt input has blank LINES.
|
||||
Consider newlines to be intervening delimiters, meaning the empty
|
||||
\"logical\" line between a trailing newline and `eob' constitutes
|
||||
a separate message."
|
||||
(pcase-let ((`(,total ,pad ,strip)(erc--count-blank-lines lines)))
|
||||
(cond ((zerop total) nil)
|
||||
((and erc-warn-about-blank-lines erc-send-whitespace-lines)
|
||||
(let (msg args)
|
||||
(unless (zerop strip)
|
||||
(push "stripping (%d)" msg)
|
||||
(push strip args))
|
||||
(unless (zerop pad)
|
||||
(when msg
|
||||
(push "and" msg))
|
||||
(push "padding (%d)" msg)
|
||||
(push pad args))
|
||||
(when msg
|
||||
(push "blank" msg)
|
||||
(push (if (> (apply #'+ args) 1) "lines" "line") msg))
|
||||
(when msg
|
||||
(setf msg (nreverse msg)
|
||||
(car msg) (capitalize (car msg))))
|
||||
(when msg
|
||||
(push (apply #'format (string-join msg " ") (nreverse args))
|
||||
erc--check-prompt-explanation)
|
||||
nil)))
|
||||
(erc-warn-about-blank-lines
|
||||
(concat (if (= total 1)
|
||||
(if (zerop strip) "Blank" "Trailing")
|
||||
(if (= total strip)
|
||||
(format "%d trailing" strip)
|
||||
(format "%d blank" total)))
|
||||
(and (> total 1) (/= total strip) (not (zerop strip))
|
||||
(format " (%d trailing)" strip))
|
||||
(if (= total 1) " line" " lines")
|
||||
" detected (see `erc-send-whitespace-lines')"))
|
||||
(erc-send-whitespace-lines nil)
|
||||
(t 'invalid))))
|
||||
|
||||
(defun erc--check-prompt-input-for-point-in-bounds (_ _)
|
||||
"Return non-nil when point is before prompt."
|
||||
(when (< (point) (erc-beg-of-input-line))
|
||||
|
@ -6484,25 +6542,34 @@ is empty or consists of one or more spaces, tabs, or form-feeds."
|
|||
|
||||
(defvar erc--check-prompt-input-functions
|
||||
'(erc--check-prompt-input-for-point-in-bounds
|
||||
erc--check-prompt-input-for-something
|
||||
erc--check-prompt-input-for-multiline-blanks
|
||||
erc--check-prompt-input-for-running-process
|
||||
erc--check-prompt-input-for-excess-lines
|
||||
erc--check-prompt-input-for-multiline-command)
|
||||
"Validators for user input typed at prompt.
|
||||
Called with latest input string submitted by user and the list of
|
||||
lines produced by splitting it. If any member function returns
|
||||
non-nil, processing is abandoned and input is left untouched.
|
||||
When the returned value is a string, ERC passes it to `erc-error'.")
|
||||
Called with two arguments: the current input submitted by the
|
||||
user, as a string, along with the same input as a list of
|
||||
strings. If any member function returns non-nil, ERC abandons
|
||||
processing and leaves pending input untouched in the prompt area.
|
||||
When the returned value is a string, ERC passes it to
|
||||
`user-error'. Any other non-nil value tells ERC to abort
|
||||
silently. If all members return nil, and the variable
|
||||
`erc--check-prompt-explanation' is a nonempty list of strings,
|
||||
ERC prints them as a single message joined by newlines.")
|
||||
|
||||
(defun erc--run-input-validation-checks (state)
|
||||
"Run input checkers from STATE, an `erc--input-split' object."
|
||||
(when-let ((msg (run-hook-with-args-until-success
|
||||
'erc--check-prompt-input-functions
|
||||
(erc--input-split-string state)
|
||||
(erc--input-split-lines state))))
|
||||
(unless (stringp msg)
|
||||
(setq msg (format "Input error: %S" msg)))
|
||||
(user-error msg)))
|
||||
(let* ((erc--check-prompt-explanation nil)
|
||||
(msg (run-hook-with-args-until-success
|
||||
'erc--check-prompt-input-functions
|
||||
(erc--input-split-string state)
|
||||
(erc--input-split-lines state))))
|
||||
(cond ((stringp msg) (user-error msg))
|
||||
(msg (push msg (erc--input-split-abortp state)))
|
||||
(erc--check-prompt-explanation
|
||||
(message "%s" (string-join (nreverse erc--check-prompt-explanation)
|
||||
"\n"))))))
|
||||
|
||||
(defun erc-send-current-line ()
|
||||
"Parse current line and send it to IRC."
|
||||
|
@ -6526,8 +6593,9 @@ When the returned value is a string, ERC passes it to `erc-error'.")
|
|||
str erc--input-line-delim-regexp)
|
||||
:cmdp (string-match erc-command-regexp str))))
|
||||
(run-hook-with-args 'erc--input-review-functions state)
|
||||
(let ((inhibit-read-only t)
|
||||
(old-buf (current-buffer)))
|
||||
(when-let (((not (erc--input-split-abortp state)))
|
||||
(inhibit-read-only t)
|
||||
(old-buf (current-buffer)))
|
||||
(progn ; unprogn this during next major surgery
|
||||
(erc-set-active-buffer (current-buffer))
|
||||
;; Kill the input and the prompt
|
||||
|
@ -6556,12 +6624,11 @@ When the returned value is a string, ERC passes it to `erc-error'.")
|
|||
(erc-end-of-input-line)))
|
||||
|
||||
(defun erc--discard-trailing-multiline-nulls (state)
|
||||
"Ensure last line of STATE's string is non-null.
|
||||
But only when `erc-send-whitespace-lines' is non-nil. STATE is
|
||||
an `erc--input-split' object."
|
||||
(when (and erc-send-whitespace-lines (erc--input-split-lines state))
|
||||
"Remove trailing empty lines from STATE, an `erc--input-split' object.
|
||||
When all lines are empty, remove all but the first."
|
||||
(when (erc--input-split-lines state)
|
||||
(let ((reversed (nreverse (erc--input-split-lines state))))
|
||||
(while (and reversed (string-empty-p (car reversed)))
|
||||
(while (and (cdr reversed) (string-empty-p (car reversed)))
|
||||
(setq reversed (cdr reversed)))
|
||||
(setf (erc--input-split-lines state) (nreverse reversed)))))
|
||||
|
||||
|
@ -6581,7 +6648,7 @@ multiline input. Optionally readjust lines to protocol length
|
|||
limits and pad empty ones, knowing full well that additional
|
||||
processing may still corrupt messages before they reach the send
|
||||
queue. Expect LINES-OBJ to be an `erc--input-split' object."
|
||||
(when (or erc-send-pre-hook erc-pre-send-functions)
|
||||
(progn ; FIXME remove `progn' after code review.
|
||||
(with-suppressed-warnings ((lexical str) (obsolete erc-send-this))
|
||||
(defvar str) ; see note in string `erc-send-input'.
|
||||
(let* ((str (string-join (erc--input-split-lines lines-obj) "\n"))
|
||||
|
|
|
@ -292,7 +292,7 @@
|
|||
(cl-incf counter))))
|
||||
erc-accidental-paste-threshold-seconds
|
||||
erc-insert-modify-hook
|
||||
erc--input-review-functions
|
||||
(erc--input-review-functions erc--input-review-functions)
|
||||
erc-send-completed-hook)
|
||||
|
||||
(ert-info ("Server buffer")
|
||||
|
@ -357,6 +357,9 @@
|
|||
(should (= (point) erc-input-marker))
|
||||
(insert "/query bob")
|
||||
(erc-send-current-line)
|
||||
;; Last command not inserted
|
||||
(save-excursion (forward-line -1)
|
||||
(should (looking-at "<tester> Howdy")))
|
||||
;; Query does not redraw (nor /help, only message input)
|
||||
(should (looking-back "#chan@ServNet 11> "))
|
||||
;; No sign of old prompts
|
||||
|
@ -877,11 +880,12 @@
|
|||
(with-current-buffer (get-buffer-create "*#fake*")
|
||||
(erc-mode)
|
||||
(erc-tests--send-prep)
|
||||
(setq erc-server-current-nick "tester")
|
||||
(setq-local erc-last-input-time 0)
|
||||
(should-not (local-variable-if-set-p 'erc-send-completed-hook))
|
||||
(set (make-local-variable 'erc-send-completed-hook) nil) ; skip t (globals)
|
||||
;; Just in case erc-ring-mode is already on
|
||||
(setq-local erc--input-review-functions nil)
|
||||
(setq-local erc--input-review-functions erc--input-review-functions)
|
||||
(add-hook 'erc--input-review-functions #'erc-add-to-input-ring)
|
||||
;;
|
||||
(cl-letf (((symbol-function 'erc-process-input-line)
|
||||
|
@ -1056,43 +1060,6 @@
|
|||
(should (equal '("" "" "") (split-string "\n\n" p)))
|
||||
(should (equal '("" "" "") (split-string "\n\r" p)))))
|
||||
|
||||
(ert-deftest erc--blank-in-multiline-input-p ()
|
||||
(let ((check (lambda (s)
|
||||
(erc--blank-in-multiline-input-p
|
||||
(split-string s erc--input-line-delim-regexp)))))
|
||||
|
||||
(ert-info ("With `erc-send-whitespace-lines'")
|
||||
(let ((erc-send-whitespace-lines t))
|
||||
(should (funcall check ""))
|
||||
(should-not (funcall check "\na"))
|
||||
(should-not (funcall check "/msg a\n")) ; real /cmd
|
||||
(should-not (funcall check "a\n\nb")) ; "" allowed
|
||||
(should-not (funcall check "/msg a\n\nb")) ; non-/cmd
|
||||
(should-not (funcall check " "))
|
||||
(should-not (funcall check "\t"))
|
||||
(should-not (funcall check "a\nb"))
|
||||
(should-not (funcall check "a\n "))
|
||||
(should-not (funcall check "a\n \t"))
|
||||
(should-not (funcall check "a\n \f"))
|
||||
(should-not (funcall check "a\n \nb"))
|
||||
(should-not (funcall check "a\n \t\nb"))
|
||||
(should-not (funcall check "a\n \f\nb"))))
|
||||
|
||||
(should (funcall check ""))
|
||||
(should (funcall check " "))
|
||||
(should (funcall check "\t"))
|
||||
(should (funcall check "a\n\nb"))
|
||||
(should (funcall check "a\n\nb"))
|
||||
(should (funcall check "a\n "))
|
||||
(should (funcall check "a\n \t"))
|
||||
(should (funcall check "a\n \f"))
|
||||
(should (funcall check "a\n \nb"))
|
||||
(should (funcall check "a\n \t\nb"))
|
||||
|
||||
(should-not (funcall check "a\rb"))
|
||||
(should-not (funcall check "a\nb"))
|
||||
(should-not (funcall check "a\r\nb"))))
|
||||
|
||||
(defun erc-tests--with-process-input-spy (test)
|
||||
(with-current-buffer (get-buffer-create "FakeNet")
|
||||
(let* ((erc--input-review-functions
|
||||
|
@ -1138,7 +1105,7 @@
|
|||
(delete-region (point) (point-max))
|
||||
(insert "one\n")
|
||||
(let ((e (should-error (erc-send-current-line))))
|
||||
(should (equal "Blank line - ignoring..." (cadr e))))
|
||||
(should (string-prefix-p "Trailing line detected" (cadr e))))
|
||||
(goto-char (point-max))
|
||||
(ert-info ("Input remains untouched")
|
||||
(should (save-excursion (goto-char erc-input-marker)
|
||||
|
@ -1180,6 +1147,137 @@
|
|||
|
||||
(should (consp erc-last-input-time)))))
|
||||
|
||||
(ert-deftest erc--discard-trailing-multiline-nulls ()
|
||||
(pcase-dolist (`(,input ,want) '((("") (""))
|
||||
(("" "") (""))
|
||||
(("a") ("a"))
|
||||
(("a" "") ("a"))
|
||||
(("" "a") ("" "a"))
|
||||
(("" "a" "") ("" "a"))))
|
||||
(ert-info ((format "Input: %S, want: %S" input want))
|
||||
(let ((s (make-erc--input-split :lines input)))
|
||||
(erc--discard-trailing-multiline-nulls s)
|
||||
(should (equal (erc--input-split-lines s) want))))))
|
||||
|
||||
(ert-deftest erc--count-blank-lines ()
|
||||
(pcase-dolist (`(,input ,want) '((() (0 0 0))
|
||||
(("") (1 1 0))
|
||||
(("" "") (2 1 1))
|
||||
(("" "" "") (3 1 2))
|
||||
((" " "") (2 0 1))
|
||||
((" " "" "") (3 0 2))
|
||||
(("" " " "") (3 1 1))
|
||||
(("" "" " ") (3 2 0))
|
||||
(("a") (0 0 0))
|
||||
(("a" "") (1 0 1))
|
||||
(("a" " " "") (2 0 1))
|
||||
(("a" "" "") (2 0 2))
|
||||
(("a" "b") (0 0 0))
|
||||
(("a" "" "b") (1 1 0))
|
||||
(("a" " " "b") (1 0 0))
|
||||
(("" "a") (1 1 0))
|
||||
((" " "a") (1 0 0))
|
||||
(("" "a" "") (2 1 1))
|
||||
(("" " " "a" "" " ") (4 2 0))
|
||||
(("" " " "a" "" " " "") (5 2 1))))
|
||||
(ert-info ((format "Input: %S, want: %S" input want))
|
||||
(should (equal (erc--count-blank-lines input) want)))))
|
||||
|
||||
;; Opt `wb': `erc-warn-about-blank-lines'
|
||||
;; Opt `sw': `erc-send-whitespace-lines'
|
||||
;; `s': " \n",`a': "a\n",`b': "b\n"
|
||||
(defvar erc-tests--check-prompt-input--expect
|
||||
;; opts "" " " "\n" "\n " " \n" "\n\n" "a\n" "a\n " "a\n \nb"
|
||||
'(((+wb -sw) err err err err err err err err err)
|
||||
((-wb -sw) nop nop nop nop nop nop nop nop nop)
|
||||
((+wb +sw) err (s) (0 s) (1 s s) (s) (0 s) (0 a) (a s) (a s b))
|
||||
((-wb +sw) nop (s) (s) (s s) (s) (s) (a) (a s) (a s b))))
|
||||
|
||||
;; Help messages echoed (not IRC message) was emitted
|
||||
(defvar erc-tests--check-prompt-input-messages
|
||||
'("Stripping" "Padding"))
|
||||
|
||||
(ert-deftest erc--check-prompt-input-for-multiline-blanks ()
|
||||
(erc-tests--with-process-input-spy
|
||||
(lambda (next)
|
||||
(erc-tests--set-fake-server-process "sleep" "1")
|
||||
(should-not erc-send-whitespace-lines)
|
||||
(should erc-warn-about-blank-lines)
|
||||
|
||||
(pcase-dolist (`((,wb ,sw) . ,ex) erc-tests--check-prompt-input--expect)
|
||||
(let ((print-escape-newlines t)
|
||||
(erc-warn-about-blank-lines (eq wb '+wb))
|
||||
(erc-send-whitespace-lines (eq sw '+sw))
|
||||
(samples '("" " " "\n" "\n " " \n" "\n\n"
|
||||
"a\n" "a\n " "a\n \nb")))
|
||||
(setq ex `(,@ex (a) (a b)) ; baseline, same for all combos
|
||||
samples `(,@samples "a" "a\nb"))
|
||||
(dolist (input samples)
|
||||
(insert input)
|
||||
(ert-info ((format "Opts: %S, Input: %S, want: %S"
|
||||
(list wb sw) input (car ex)))
|
||||
(ert-with-message-capture messages
|
||||
(pcase-exhaustive (pop ex)
|
||||
('err (let ((e (should-error (erc-send-current-line))))
|
||||
(should (string-match (rx (| "trailing" "blank"))
|
||||
(cadr e))))
|
||||
(should (equal (erc-user-input) input))
|
||||
(should-not (funcall next)))
|
||||
('nop (erc-send-current-line)
|
||||
(should (equal (erc-user-input) input))
|
||||
(should-not (funcall next)))
|
||||
('clr (erc-send-current-line)
|
||||
(should (string-empty-p (erc-user-input)))
|
||||
(should-not (funcall next)))
|
||||
((and (pred consp) v)
|
||||
(erc-send-current-line)
|
||||
(should (string-empty-p (erc-user-input)))
|
||||
(setq v (reverse v)) ; don't use `nreverse' here
|
||||
(while v
|
||||
(pcase (pop v)
|
||||
((and (pred integerp) n)
|
||||
(should (string-search
|
||||
(nth n erc-tests--check-prompt-input-messages)
|
||||
messages)))
|
||||
('s (should (equal " \n" (car (funcall next)))))
|
||||
('a (should (equal "a\n" (car (funcall next)))))
|
||||
('b (should (equal "b\n" (car (funcall next)))))))
|
||||
(should-not (funcall next))))))
|
||||
(delete-region erc-input-marker (point-max))))))))
|
||||
|
||||
(ert-deftest erc--check-prompt-input-for-multiline-blanks/explanations ()
|
||||
(should erc-warn-about-blank-lines)
|
||||
(should-not erc-send-whitespace-lines)
|
||||
|
||||
(let ((erc-send-whitespace-lines t))
|
||||
(pcase-dolist (`(,input ,msg)
|
||||
'((("") "Padding (1) blank line")
|
||||
(("" " ") "Padding (1) blank line")
|
||||
((" " "") "Stripping (1) blank line")
|
||||
(("a" "") "Stripping (1) blank line")
|
||||
(("" "") "Stripping (1) and padding (1) blank lines")
|
||||
(("" "" "") "Stripping (2) and padding (1) blank lines")
|
||||
(("" "a" "" "b" "" "c" "" "")
|
||||
"Stripping (2) and padding (3) blank lines")))
|
||||
(ert-info ((format "Input: %S, Msg: %S" input msg))
|
||||
(let (erc--check-prompt-explanation)
|
||||
(should-not (erc--check-prompt-input-for-multiline-blanks nil input))
|
||||
(should (equal (list msg) erc--check-prompt-explanation))))))
|
||||
|
||||
(pcase-dolist (`(,input ,msg)
|
||||
'((("") "Blank line detected")
|
||||
(("" " ") "2 blank lines detected")
|
||||
((" " "") "2 blank (1 trailing) lines detected")
|
||||
(("a" "") "Trailing line detected")
|
||||
(("" "") "2 blank (1 trailing) lines detected")
|
||||
(("a" "" "") "2 trailing lines detected")
|
||||
(("" "a" "" "b" "" "c" "" "")
|
||||
"5 blank (2 trailing) lines detected")))
|
||||
(ert-info ((format "Input: %S, Msg: %S" input msg))
|
||||
(let ((rv (erc--check-prompt-input-for-multiline-blanks nil input)))
|
||||
(should (equal (concat msg " (see `erc-send-whitespace-lines')")
|
||||
rv ))))))
|
||||
|
||||
(ert-deftest erc-send-whitespace-lines ()
|
||||
(erc-tests--with-process-input-spy
|
||||
(lambda (next)
|
||||
|
@ -1196,7 +1294,7 @@
|
|||
(erc-bol)
|
||||
(should (eq (point) (point-max))))
|
||||
(should (equal (funcall next) '("two\n" nil t)))
|
||||
(should (equal (funcall next) '("\n" nil t)))
|
||||
(should (equal (funcall next) '(" \n" nil t)))
|
||||
(should (equal (funcall next) '("one\n" nil t))))
|
||||
|
||||
(ert-info ("Multiline hunk with trailing newline filtered")
|
||||
|
|
Loading…
Add table
Reference in a new issue