From 10237840d03c4ba647fd3045ee500af950a5df6e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@neverwas.me> Date: Wed, 27 Apr 2022 02:27:32 -0700 Subject: [PATCH] Optionally prevent sending multiline input in ERC * lisp/erc/erc.el (erc-inhibit-multiline-input): Add option to cap the number of lines to be sent before admonishing the user. (erc-ask-about-multiline-input): Add option to ask instead of warning user when `erc-inhibit-multiline-input' is reached. (erc--check-prompt-input-for-excess-lines): Add validator to possibly warn when too many lines are submitted for transmission. * test/lisp/erc/erc-tests.el (erc--check-prompt-input-for-excess-lines): Add test. (Bug#54536) --- lisp/erc/erc.el | 34 +++++++++++++++++++++++++++++++++- test/lisp/erc/erc-tests.el | 25 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 89ce713fe02..6f17e4ee7b7 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -260,6 +260,20 @@ node `(auth) Top' and info node `(erc) Connecting'.") :group 'erc :type 'boolean) +(defcustom erc-inhibit-multiline-input nil + "Conditionally disallow input consisting of multiple lines. +Issue an error when the number of input lines submitted for +sending exceeds this value." + :package-version '(ERC . "5.4.1") ; FIXME match to next release + :group 'erc + :type '(choice integer boolean)) + +(defcustom erc-ask-about-multiline-input nil + "Ask to ignore `erc-inhibit-multiline-input' when tripped." + :package-version '(ERC . "5.4.1") ; FIXME match to next release + :group 'erc + :type 'boolean) + (defcustom erc-prompt-hidden ">" "Text to show in lieu of the prompt when hidden." :package-version '(ERC . "5.4.1") ; FIXME increment on next ELPA release @@ -5890,6 +5904,23 @@ is empty or consists of one or more spaces, tabs, or form-feeds." (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 + ;; Assume `erc--discard-trailing-multiline-nulls' is set to run + (let ((reversed (seq-drop-while #'string-empty-p (reverse lines))) + (max (if (eq erc-inhibit-multiline-input t) + 2 + erc-inhibit-multiline-input)) + (seen 0) + msg) + (while (and (pop reversed) (< (cl-incf seen) max))) + (when (= seen max) + (setq msg (format "(exceeded by %d)" (1+ (length reversed)))) + (unless (and erc-ask-about-multiline-input + (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) @@ -5911,7 +5942,8 @@ 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-multiline-blanks - erc--check-prompt-input-for-running-process) + erc--check-prompt-input-for-running-process + erc--check-prompt-input-for-excess-lines) "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 diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 986988a3356..62bea8fb3f0 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -797,6 +797,31 @@ (should (equal (funcall next) '("there\n" nil t))) (should-not (funcall next)))))) +(ert-deftest erc--check-prompt-input-for-excess-lines () + (ert-info ("Without `erc-inhibit-multiline-input'") + (should-not erc-inhibit-multiline-input) + (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b")))) + + (ert-info ("With `erc-inhibit-multiline-input' as t (2)") + (let ((erc-inhibit-multiline-input t)) + (should-not (erc--check-prompt-input-for-excess-lines "" '("a"))) + (should-not (erc--check-prompt-input-for-excess-lines "" '("a" ""))) + (should (erc--check-prompt-input-for-excess-lines "" '("a" "b"))))) + + (ert-info ("With `erc-inhibit-multiline-input' as 3") + (let ((erc-inhibit-multiline-input 3)) + (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b"))) + (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b" ""))) + (should (erc--check-prompt-input-for-excess-lines "" '("a" "b" "c"))))) + + (ert-info ("With `erc-ask-about-multiline-input'") + (let ((erc-inhibit-multiline-input t) + (erc-ask-about-multiline-input t)) + (ert-simulate-keys '(?n ?\r ?y ?\r) + (should (erc--check-prompt-input-for-excess-lines "" '("a" "b"))) + (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b"))))) + (should-not erc-ask-about-multiline-input))) + ;; The point of this test is to ensure output is handled identically ;; regardless of whether a command handler is summoned. -- 2.39.5